package com.todo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonArray;
import com.todo.config.AiConfig;
import com.todo.entity.Todo;
import com.todo.mapper.TodoMapper;
import com.todo.service.AiService;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * AI服务实现类
 */
@Slf4j
@Service
public class AiServiceImpl implements AiService {

    @Autowired
    private AiConfig aiConfig;

    @Autowired
    private TodoMapper todoMapper;

    private final Gson gson = new Gson();

    /**
     * 生成用户的每日摘要
     * 该方法重写了接口或父类的方法，专注于生成特定用户的一天摘要信息
     * 
     * @param userId 用户ID，用于标识需要生成摘要的用户
     * @return 返回用户的每日摘要信息字符串
     */
    @Override
    public String generateDailySummary(Long userId) {
        // 获取当前日期，用作摘要的开始和结束日期
        LocalDate today = LocalDate.now();
        // 调用通用摘要生成方法，针对特定用户和日期生成摘要
        return generateSummary(userId, today, today);
    }

    @Override
    public String generateWeeklySummary(Long userId) {
        LocalDate today = LocalDate.now();
        LocalDate startOfWeek = today.minusDays(today.getDayOfWeek().getValue() - 1);
        LocalDate endOfWeek = startOfWeek.plusDays(6);
        return generateSummary(userId, startOfWeek, endOfWeek);
    }

    /**
     * 生成指定用户和日期范围内的待办事项总结
     * 
     * @param userId 用户ID，用于筛选待办事项
     * @param startDate 起始日期，用于筛选待办事项
     * @param endDate 结束日期，用于筛选待办事项
     * @return 生成的总结字符串，如果发生错误或没有待办事项，则返回相应的错误信息或提示信息
     */
    @Override
    public String generateSummary(Long userId, LocalDate startDate, LocalDate endDate) {
        try {
            // 获取指定日期范围内的待办事项
            QueryWrapper<Todo> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId)
                       .between("due_date", startDate, endDate)
                       .ne("status", 2) // 排除已删除的
                       .orderByAsc("due_date")
                       .orderByAsc("due_time");
            
            List<Todo> todos = todoMapper.selectList(queryWrapper);
            
            if (todos.isEmpty()) {
                return "在指定时间范围内没有待办事项。";
            }
    
            // 构建提示词
            String prompt = buildPrompt(todos, startDate, endDate);
            
            // 调用AI模型生成总结
            return callAiModel(prompt, aiConfig.getDefaultProvider());
            
        } catch (Exception e) {
            log.error("生成AI总结失败", e);
            return "生成总结时发生错误，请稍后重试。";
        }
    }

    /**
     * 调用AI模型接口
     * 
     * 本方法根据不同的AI服务提供商调用相应的AI模型，并返回结果
     * 如果提供商不支持或调用过程中出现异常，将返回相应的错误信息或提示
     * 
     * @param prompt 用户的查询或问题，作为AI模型的输入
     * @param provider AI服务提供商的名称，用于选择调用的AI模型
     * @return AI模型的响应或错误提示
     */
    @Override
    public String callAiModel(String prompt, String provider) {
        try {
            // 根据AI服务提供商的名称选择相应的AI模型进行调用
            switch (provider.toLowerCase()) {
                case "openai":
                    return callOpenAI(prompt);
                case "gemini":
                    return callGemini(prompt);
                case "qwen":
                    return callQwen(prompt);
                default:
                    // 如果提供商不支持，抛出异常
                    throw new IllegalArgumentException("不支持的AI服务提供商: " + provider);
            }
        } catch (Exception e) {
            // 记录调用AI模型时发生的异常
            log.error("调用AI模型失败: {}", e.getMessage());
            // 返回用户友好的错误提示
            return "AI服务暂时不可用，请稍后重试。";
        }
    }

    /**
     * 调用OpenAI API
     */
    private String callOpenAI(String prompt) throws IOException {
        AiConfig.ProviderConfig config = aiConfig.getOpenai();
        
        JsonObject requestBody = new JsonObject();
        requestBody.addProperty("model", config.getModel());
        requestBody.addProperty("max_tokens", config.getMaxTokens());
        
        JsonArray messages = new JsonArray();
        JsonObject message = new JsonObject();
        message.addProperty("role", "user");
        message.addProperty("content", prompt);
        messages.add(message);
        requestBody.add("messages", messages);

        Request request = new Request.Builder()
                .url(config.getBaseUrl() + "/chat/completions")
                .addHeader("Authorization", "Bearer " + config.getApiKey())
                .addHeader("Content-Type", "application/json")
                .post(RequestBody.create(requestBody.toString(), MediaType.get("application/json")))
                .build();

        try (Response response = getHttpClient().newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("OpenAI API调用失败: " + response.code());
            }
            
            JsonObject responseBody = gson.fromJson(response.body().string(), JsonObject.class);
            return responseBody.getAsJsonArray("choices")
                    .get(0).getAsJsonObject()
                    .getAsJsonObject("message")
                    .get("content").getAsString();
        }
    }

    /**
     * 调用Gemini API
     */
    private String callGemini(String prompt) throws IOException {
        AiConfig.ProviderConfig config = aiConfig.getGemini();
        
        JsonObject requestBody = new JsonObject();
        JsonArray contents = new JsonArray();
        JsonObject content = new JsonObject();
        JsonArray parts = new JsonArray();
        JsonObject part = new JsonObject();
        part.addProperty("text", prompt);
        parts.add(part);
        content.add("parts", parts);
        contents.add(content);
        requestBody.add("contents", contents);

        Request request = new Request.Builder()
                .url(config.getBaseUrl() + "/v1beta/models/" + config.getModel() + ":generateContent?key=" + config.getApiKey())
                .addHeader("Content-Type", "application/json")
                .post(RequestBody.create(requestBody.toString(), MediaType.get("application/json")))
                .build();

        try (Response response = getHttpClient().newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Gemini API调用失败: " + response.code());
            }
            
            JsonObject responseBody = gson.fromJson(response.body().string(), JsonObject.class);
            return responseBody.getAsJsonArray("candidates")
                    .get(0).getAsJsonObject()
                    .getAsJsonObject("content")
                    .getAsJsonArray("parts")
                    .get(0).getAsJsonObject()
                    .get("text").getAsString();
        }
    }

    /**
     * 调用通义千问API
     */
    private String callQwen(String prompt) throws IOException {
        AiConfig.ProviderConfig config = aiConfig.getQwen();
        
        JsonObject requestBody = new JsonObject();
        requestBody.addProperty("model", config.getModel());
        
        JsonObject input = new JsonObject();
        JsonArray messages = new JsonArray();
        JsonObject message = new JsonObject();
        message.addProperty("role", "user");
        message.addProperty("content", prompt);
        messages.add(message);
        input.add("messages", messages);
        requestBody.add("input", input);
        
        JsonObject parameters = new JsonObject();
        parameters.addProperty("max_tokens", config.getMaxTokens());
        requestBody.add("parameters", parameters);

        Request request = new Request.Builder()
                .url(config.getBaseUrl() + "/compatible-mode/v1/chat/completions")
                .addHeader("Authorization", "Bearer " + config.getApiKey())
                .addHeader("Content-Type", "application/json")
                .post(RequestBody.create(requestBody.toString(), MediaType.get("application/json")))
                .build();

        try (Response response = getHttpClient().newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("通义千问API调用失败: " + response.code());
            }
            
            JsonObject responseBody = gson.fromJson(response.body().string(), JsonObject.class);
            return responseBody.getAsJsonArray("choices")
                    .get(0).getAsJsonObject()
                    .getAsJsonObject("message")
                    .get("content").getAsString();
        }
    }

    /**
     * 构建AI提示词
     */
    private String buildPrompt(List<Todo> todos, LocalDate startDate, LocalDate endDate) {
        StringBuilder prompt = new StringBuilder();
        
        String dateRange = startDate.equals(endDate) ? 
            startDate.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")) :
            startDate.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")) + " 至 " + 
            endDate.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"));
            
        prompt.append("请为我总结 ").append(dateRange).append(" 的待办事项情况。\n\n");
        prompt.append("待办事项列表：\n");
        
        // 分类整理待办事项
        List<Todo> pending = todos.stream().filter(t -> t.getStatus() == 0).collect(Collectors.toList());
        List<Todo> completed = todos.stream().filter(t -> t.getStatus() == 1).collect(Collectors.toList());
        
        if (!pending.isEmpty()) {
            prompt.append("\n【待完成】:\n");
            for (Todo todo : pending) {
                prompt.append("- ").append(todo.getTitle());
                if (todo.getDueTime() != null) {
                    prompt.append(" (").append(todo.getDueTime()).append(")");
                }
                if (todo.getPriority() != null && todo.getPriority() > 1) {
                    prompt.append(" [优先级: ").append(getPriorityText(todo.getPriority())).append("]");
                }
                prompt.append("\n");
            }
        }
        
        if (!completed.isEmpty()) {
            prompt.append("\n【已完成】:\n");
            for (Todo todo : completed) {
                prompt.append("- ").append(todo.getTitle());
                if (todo.getCompletedAt() != null) {
                    prompt.append(" (已于 ").append(todo.getCompletedAt().format(DateTimeFormatter.ofPattern("MM-dd HH:mm"))).append(" 完成)");
                }
                prompt.append("\n");
            }
        }
        
        prompt.append("\n请从以下几个方面进行总结：\n");
        prompt.append("1. 完成情况统计（完成率、总体表现）\n");
        prompt.append("2. 时间管理分析（是否按时完成、时间分配是否合理）\n");
        prompt.append("3. 任务优先级处理情况\n");
        prompt.append("4. 改进建议（如何提高效率、更好的时间规划等）\n");
        prompt.append("5. 如果待办中存在名称的，请将名称剔除，名称实例：“周栋”、“马冬梅”、“王二十”等\n");
        prompt.append("6. 待办总结。你是一位优秀的项目管理专家，请将所有的待办，总结输出，不要输出时间\n");
        prompt.append("\n请用Markdown格式回答，包含标题、列表、重点强调等格式。提供一个结构清晰、内容丰富但是不要太碎的总结报告。");
        prompt.append("\n\n示例格式：");
        prompt.append("\n## 📊 待办事项总结");
        prompt.append("\n");
        /* prompt.append("\n### ⭐ 总结");
        prompt.append("\n- **事项总结**: ...");
        prompt.append("\n"); */
        prompt.append("\n### ✅ 完成情况"); 
        prompt.append("\n- **完成率**: XX%");
        prompt.append("\n- **总体表现**: ...");
        prompt.append("\n");
        prompt.append("\n### ⏰ 时间管理");
        prompt.append("\n- ...");
        prompt.append("\n");
        prompt.append("\n### 🎯 改进建议");
        prompt.append("\n1. ...");
        prompt.append("\n2. ...");
        prompt.append("\n");
        prompt.append("\n请严格按照此格式输出，使用emoji和markdown语法。");
        
        return prompt.toString();
    }

    /**
     * 获取优先级文本
     */
    private String getPriorityText(Integer priority) {
        switch (priority) {
            case 1: return "低";
            case 2: return "中";
            case 3: return "高";
            default: return "普通";
        }
    }

    /**
     * 获取HTTP客户端（支持代理）
     */
    private OkHttpClient getHttpClient() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .connectTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(120, TimeUnit.SECONDS)
                .readTimeout(120, TimeUnit.SECONDS);

        // 如果启用了代理
        if (aiConfig.getProxy().isEnabled()) {
            Proxy proxy = new Proxy(Proxy.Type.HTTP, 
                new InetSocketAddress(aiConfig.getProxy().getHost(), aiConfig.getProxy().getPort()));
            builder.proxy(proxy);
        }

        return builder.build();
    }
} 